package cn.iocoder.yudao.module.system.util.gugu;

import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 批量查询优化器
 * 用于监控和优化批量查询性能，避免StackOverflowError
 */
@Slf4j
public class BatchQueryOptimizer {

    /**
     * 查询策略枚举
     */
    public enum QueryStrategy {
        NORMAL_BATCH,      // 正常批量查询
        SUPER_BATCH,       // 超级分批查询
        ULTRA_SIMPLE,      // 极简查询
        FALLBACK          // 降级查询
    }

    /**
     * 查询统计信息
     */
    public static class QueryStats {
        private final AtomicLong totalQueries = new AtomicLong(0);
        private final AtomicLong successfulQueries = new AtomicLong(0);
        private final AtomicLong failedQueries = new AtomicLong(0);
        private final AtomicLong totalExecutionTime = new AtomicLong(0);
        private final Map<QueryStrategy, AtomicLong> strategyUsage = new ConcurrentHashMap<>();

        public void recordQuery(QueryStrategy strategy, long executionTime, boolean success) {
            totalQueries.incrementAndGet();
            totalExecutionTime.addAndGet(executionTime);
            strategyUsage.computeIfAbsent(strategy, k -> new AtomicLong(0)).incrementAndGet();
            
            if (success) {
                successfulQueries.incrementAndGet();
            } else {
                failedQueries.incrementAndGet();
            }
        }

        public long getTotalQueries() { return totalQueries.get(); }
        public long getSuccessfulQueries() { return successfulQueries.get(); }
        public long getFailedQueries() { return failedQueries.get(); }
        public long getAverageExecutionTime() {
            long total = totalQueries.get();
            return total > 0 ? totalExecutionTime.get() / total : 0;
        }
        public Map<QueryStrategy, AtomicLong> getStrategyUsage() { return strategyUsage; }
    }

    private static final QueryStats stats = new QueryStats();

    /**
     * 数据量阈值配置
     */
    private static final int NORMAL_BATCH_SCHOOL_LIMIT = 200;
    private static final int NORMAL_BATCH_MAJOR_LIMIT = 100;
    private static final int SUPER_BATCH_SCHOOL_LIMIT = 1000;
    private static final int SUPER_BATCH_MAJOR_LIMIT = 500;

    /**
     * 根据数据量决定查询策略
     */
    public static QueryStrategy determineQueryStrategy(int schoolCount, int majorCount, int candidateCount) {
        log.debug("决定查询策略 - 学校数量：{}，专业数量：{}，候选专业数量：{}", 
            schoolCount, majorCount, candidateCount);

        // 极大数据量：使用极简查询
        if (schoolCount > SUPER_BATCH_SCHOOL_LIMIT || majorCount > SUPER_BATCH_MAJOR_LIMIT) {
            log.warn("数据量极大，使用极简查询策略");
            return QueryStrategy.ULTRA_SIMPLE;
        }

        // 大数据量：使用超级分批查询
        if (schoolCount > NORMAL_BATCH_SCHOOL_LIMIT || majorCount > NORMAL_BATCH_MAJOR_LIMIT) {
            log.info("数据量较大，使用超级分批查询策略");
            return QueryStrategy.SUPER_BATCH;
        }

        // 正常数据量：使用正常批量查询
        log.debug("数据量正常，使用正常批量查询策略");
        return QueryStrategy.NORMAL_BATCH;
    }

    /**
     * 记录查询统计
     */
    public static void recordQueryExecution(QueryStrategy strategy, long executionTime, boolean success) {
        stats.recordQuery(strategy, executionTime, success);
        
        if (!success) {
            log.warn("查询策略 {} 执行失败，耗时：{}ms", strategy, executionTime);
        } else {
            log.debug("查询策略 {} 执行成功，耗时：{}ms", strategy, executionTime);
        }
    }

    /**
     * 获取查询统计信息
     */
    public static QueryStats getQueryStats() {
        return stats;
    }

    /**
     * 打印统计信息
     */
    public static void printStats() {
        log.info("=== 批量查询统计信息 ===");
        log.info("总查询次数: {}", stats.getTotalQueries());
        log.info("成功查询次数: {}", stats.getSuccessfulQueries());
        log.info("失败查询次数: {}", stats.getFailedQueries());
        log.info("平均执行时间: {}ms", stats.getAverageExecutionTime());
        log.info("成功率: {}%", stats.getTotalQueries() > 0 ? 
            (stats.getSuccessfulQueries() * 100.0 / stats.getTotalQueries()) : 0);
        
        log.info("各策略使用情况:");
        stats.getStrategyUsage().forEach((strategy, count) -> 
            log.info("  {}: {} 次", strategy, count.get()));
        log.info("=== 统计信息结束 ===");
    }

    /**
     * 清空统计信息
     */
    public static void clearStats() {
        stats.totalQueries.set(0);
        stats.successfulQueries.set(0);
        stats.failedQueries.set(0);
        stats.totalExecutionTime.set(0);
        stats.strategyUsage.clear();
        log.info("批量查询统计信息已清空");
    }

    /**
     * 计算合适的批次大小
     */
    public static int calculateOptimalBatchSize(int totalSize, QueryStrategy strategy) {
        switch (strategy) {
            case NORMAL_BATCH:
                return Math.min(100, Math.max(10, totalSize / 10));
            case SUPER_BATCH:
                return Math.min(20, Math.max(5, totalSize / 50));
            case ULTRA_SIMPLE:
                return Math.min(10, Math.max(1, totalSize / 100));
            case FALLBACK:
                return Math.min(50, Math.max(5, totalSize / 20));
            default:
                return 20;
        }
    }

    /**
     * 检查是否应该使用多线程
     */
    public static boolean shouldUseMultiThread(int candidateCount, QueryStrategy strategy) {
        // 数据量过大或过小时都不使用多线程
        if (candidateCount < 50 || candidateCount > 5000) {
            return false;
        }

        // 极简查询策略不使用多线程
        if (strategy == QueryStrategy.ULTRA_SIMPLE) {
            return false;
        }

        return true;
    }

    /**
     * 获取推荐的线程池大小
     */
    public static int getRecommendedThreadPoolSize(int candidateCount) {
        if (candidateCount < 100) {
            return 2;
        } else if (candidateCount < 500) {
            return 4;
        } else if (candidateCount < 2000) {
            return 6;
        } else {
            return 8;
        }
    }

    /**
     * 检查内存使用情况
     */
    public static boolean isMemoryUsageAcceptable() {
        Runtime runtime = Runtime.getRuntime();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        double usagePercentage = (double) usedMemory / totalMemory * 100;

        log.debug("内存使用情况 - 已使用: {}MB, 总内存: {}MB, 使用率: {:.2f}%",
            usedMemory / 1024 / 1024, totalMemory / 1024 / 1024, usagePercentage);

        return usagePercentage < 80; // 内存使用率低于80%时认为可接受
    }

    /**
     * 建议垃圾回收
     */
    public static void suggestGarbageCollection() {
        if (!isMemoryUsageAcceptable()) {
            log.info("内存使用率较高，建议进行垃圾回收");
            System.gc();
        }
    }
}
